package com.linkhub.oms.admin.modules.stock.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.google.common.collect.Maps;
import com.linkhub.oms.admin.common.exception.ExceptionFactory;
import com.linkhub.oms.admin.modules.stock.domain.dto.ConfirmInboundDTO;
import com.linkhub.oms.admin.modules.stock.domain.dto.PreemptionDTO;
import com.linkhub.oms.admin.modules.stock.domain.dto.StockCheckDTO;
import com.linkhub.oms.admin.modules.stock.enums.BatchStatus;
import com.linkhub.oms.admin.modules.stock.enums.ProductType;
import com.linkhub.oms.common.enums.IEnumConvert;
import com.linkhub.oms.common.util.json.QtFastjsonUtil;
import com.linkhub.oms.dao.mapper.BatchEntityMapper;
import com.linkhub.oms.dao.mapper.BatchRemainingEntityMapper;
import com.linkhub.oms.entity.BatchEntity;
import com.linkhub.oms.entity.BatchRemainingEntity;
import com.linkhub.oms.entity.PhysicalStockFlowEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

/**
 * @ClassName BatchServiceImpl
 * @Description TODO
 * @Author XieYu
 * @Date 2024/7/2 21:47
 * @Version 1.0
 */
@Slf4j
@Service
public class BatchBizServiceImpl {

    @Resource
    private BatchEntityMapper batchMapper;
    @Resource
    private BatchRemainingEntityMapper batchRemainingMapper;

    @Transactional(rollbackFor = Exception.class)
    public Long wmsInboundConfirm(ConfirmInboundDTO confirmInboundDTO) {
        log.info("库存管理-入库单确认-批次处理-开始：{}", QtFastjsonUtil.toJSONString(confirmInboundDTO));
        BatchEntity batch = new BatchEntity();
        batch.setUserId(confirmInboundDTO.getUserId());
        batch.setSkuId(confirmInboundDTO.getSkuId());
        batch.setManufactureNo(confirmInboundDTO.getManufactureNo());
        batch.setStashName(confirmInboundDTO.getStashName());
        batch.setSupplierId(confirmInboundDTO.getSupplierId());
        batch.setInboundNo(confirmInboundDTO.getInboundNo());
        batch.setInboundTime(DateUtil.parseLocalDateTime(confirmInboundDTO.getInboundDate(), DatePattern.NORM_DATE_PATTERN).toLocalDate());
        ProductType productType = IEnumConvert.valueOf(confirmInboundDTO.getType(), ProductType.class);
        if (productType == ProductType.GOOD) {
            batch.setGoodAmount(confirmInboundDTO.getSkuQuantity());
            batch.setBadAmount(0);
        } else {
            batch.setBadAmount(confirmInboundDTO.getSkuQuantity());
            batch.setGoodAmount(0);
        }
        long batchId = addOrUpdate(batch);
        log.info("库存管理-入库单确认-批次处理-结束，batchId: {}", batchId);
        return batchId;
    }

    @Transactional(rollbackFor = Exception.class)
    public Map<Long, Integer> batchUpdate(String userId, String skuId, String stashName, ProductType productType, int skuQuantity) {
        MPJLambdaWrapper<BatchRemainingEntity> batchRemainWrapper = JoinWrappers.lambda(BatchRemainingEntity.class);
        batchRemainWrapper.selectAs(BatchRemainingEntity::getBatchId, BatchRemainingEntity::getBatchId)
                .selectAs(BatchRemainingEntity::getGoodAmount, BatchRemainingEntity::getGoodAmount)
                .selectAs(BatchRemainingEntity::getBadAmount, BatchRemainingEntity::getBadAmount)
                .innerJoin(BatchEntity.class, on -> on.eq(BatchEntity::getId, BatchRemainingEntity::getBatchId))
                .eq(BatchEntity::getUserId, userId)
                .eq(BatchEntity::getStashName, stashName)
                .eq(BatchEntity::getSkuId, skuId)
                .ge(productType == ProductType.GOOD, BatchRemainingEntity::getGoodAmount, 0)
                .ge(productType == ProductType.BAD, BatchRemainingEntity::getBadAmount, 0)
                .orderByDesc(BatchEntity::getCreateTime)
                .orderByDesc(BatchEntity::getId);
        List<BatchRemainingEntity> batchRemainingList = batchRemainingMapper
                .selectJoinList(BatchRemainingEntity.class, batchRemainWrapper);
        if (CollUtil.isEmpty(batchRemainingList)) {
            log.error("库存盘点时，无对应批次可操作");
            throw ExceptionFactory.getI18nBizException("stock.check.no.batch.error");
        }
        Map<Long, Integer> result = Maps.newLinkedHashMap();
        if (productType == ProductType.GOOD) {
            if (skuQuantity < 0) {
//                if (MapUtil.isNotEmpty(canceledBatches)) {
//                    List<BatchRemainingEntity> cancelBatchEntities = batchRemainingMapper.selectBatchIds(canceledBatches.keySet());
//                    batchRemainingList.addAll(0, cancelBatchEntities);
//                }
                int needMinus = Math.abs(skuQuantity);
                for (BatchRemainingEntity batchRemainingEntity : batchRemainingList) {
                    if (needMinus <= 0) {
                        break;
                    }
                    if (batchRemainingEntity.getGoodAmount() <= 0) {
                        continue;
                    }
                    if (needMinus > batchRemainingEntity.getGoodAmount()) { // 需要减的比当前可用大
                        needMinus = needMinus - batchRemainingEntity.getGoodAmount(); // 剩余需要减的
                        BatchEntity batchEntity = batchMapper.selectById(batchRemainingEntity.getBatchId());
                        batchEntity.setGoodAmount(batchEntity.getGoodAmount() - batchRemainingEntity.getGoodAmount());
                        result.put(batchEntity.getId(), -batchRemainingEntity.getGoodAmount());
                        batchRemainingEntity.setGoodAmount(0);
                        batchMapper.updateById(batchEntity);
                        batchRemainingMapper.updateById(batchRemainingEntity);
                    } else {
                        BatchEntity batchEntity = batchMapper.selectById(batchRemainingEntity.getBatchId());
                        batchEntity.setGoodAmount(batchEntity.getGoodAmount() - needMinus);
                        batchRemainingEntity.setGoodAmount(batchRemainingEntity.getGoodAmount() - needMinus);
                        result.put(batchEntity.getId(), -needMinus);
                        needMinus = 0;
                        batchMapper.updateById(batchEntity);
                        batchRemainingMapper.updateById(batchRemainingEntity);
                    }
                }
            } else { // 大于0，则加到最新批次
                BatchRemainingEntity lastBatch = batchRemainingList.get(0);
                lastBatch.setGoodAmount(lastBatch.getGoodAmount() + skuQuantity);
                BatchEntity batchEntity = batchMapper.selectById(lastBatch.getBatchId());
                batchEntity.setGoodAmount(batchEntity.getGoodAmount() + skuQuantity);
                batchMapper.updateById(batchEntity);
                batchRemainingMapper.updateById(lastBatch);
                result.put(batchEntity.getId(), skuQuantity);
            }
        } else { // 次品
            if (skuQuantity < 0) {
                int needMinus = Math.abs(skuQuantity);
                for (BatchRemainingEntity batchRemainingEntity : batchRemainingList) {
                    if (needMinus <= 0) {
                        break;
                    }
                    if (batchRemainingEntity.getBadAmount() <= 0) {
                        continue;
                    }
                    if (needMinus > batchRemainingEntity.getBadAmount()) { // 需要减的比当前可用大
                        needMinus = needMinus - batchRemainingEntity.getBadAmount(); // 剩余需要减的
                        BatchEntity batchEntity = batchMapper.selectById(batchRemainingEntity.getBatchId());
                        batchEntity.setBadAmount(batchEntity.getBadAmount() - batchRemainingEntity.getBadAmount());
                        result.put(batchEntity.getId(), -batchRemainingEntity.getBadAmount());
                        batchRemainingEntity.setBadAmount(0);
                        batchMapper.updateById(batchEntity);
                        batchRemainingMapper.updateById(batchRemainingEntity);
                    } else {
                        BatchEntity batchEntity = batchMapper.selectById(batchRemainingEntity.getBatchId());
                        batchEntity.setBadAmount(batchEntity.getBadAmount() - needMinus);
                        batchRemainingEntity.setBadAmount(batchRemainingEntity.getBadAmount() - needMinus);
                        result.put(batchEntity.getId(), -needMinus);
                        needMinus = 0;
                        batchMapper.updateById(batchEntity);
                        batchRemainingMapper.updateById(batchRemainingEntity);
                    }
                }
            } else { // 大于0，则加到最新批次
                BatchRemainingEntity lastBatch = batchRemainingList.get(0);
                lastBatch.setBadAmount(lastBatch.getBadAmount() + skuQuantity);
                BatchEntity batchEntity = batchMapper.selectById(lastBatch.getBatchId());
                batchEntity.setBadAmount(batchEntity.getBadAmount() + skuQuantity);
                batchMapper.updateById(batchEntity);
                batchRemainingMapper.updateById(lastBatch);
                result.put(batchEntity.getId(), skuQuantity);
            }
        }
        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    public Map<Long, Integer> preemption(PreemptionDTO preemptionDTO) {
        MPJLambdaWrapper<BatchRemainingEntity> batchRemainWrapper = JoinWrappers.lambda(BatchRemainingEntity.class);
        batchRemainWrapper.selectAs(BatchRemainingEntity::getBatchId, BatchRemainingEntity::getBatchId)
                .selectAs(BatchRemainingEntity::getGoodAmount, BatchRemainingEntity::getGoodAmount)
                .selectAs(BatchRemainingEntity::getBadAmount, BatchRemainingEntity::getBadAmount)
                .innerJoin(BatchEntity.class, on -> on.eq(BatchEntity::getId, BatchRemainingEntity::getBatchId))
                .eq(BatchEntity::getUserId, preemptionDTO.getUserId())
                .eq(BatchEntity::getStashName, preemptionDTO.getStashName())
                .eq(BatchEntity::getSkuId, preemptionDTO.getSkuId())
                .gt(BatchRemainingEntity::getGoodAmount, 0)
                .orderByAsc(BatchEntity::getCreateTime);
        List<BatchRemainingEntity> batchRemainingList = batchRemainingMapper
                .selectJoinList(BatchRemainingEntity.class, batchRemainWrapper);

        Map<Long, Integer> result = Maps.newHashMap();
        int amount = preemptionDTO.getSkuQuantity();
        if (CollUtil.isNotEmpty(batchRemainingList)) {
            for (BatchRemainingEntity batchRemaining : batchRemainingList) {
                if (amount <= 0) {
                    break;
                }
                int preemptionAmount = amount;
                if (batchRemaining.getGoodAmount() > amount) {
                    // 此批次即可预占
                    batchRemaining.setGoodAmount(batchRemaining.getGoodAmount() - amount);
                    amount = 0;
                } else {
                    // 此批次不够预占
                    amount = amount - batchRemaining.getGoodAmount(); // 剩余需要预占的
                    preemptionAmount = batchRemaining.getGoodAmount();
                    batchRemaining.setGoodAmount(0);    // 此批次预占完
                }
                result.put(batchRemaining.getBatchId(), preemptionAmount);
                batchRemainingMapper.updateById(batchRemaining);
            }
        }

        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    public void preemptionCancel(Map<Long, Integer> batchRemainingMap) {
        batchRemainingMap.forEach((batchId, amount) -> {
            BatchRemainingEntity batchRemainingEntity = batchRemainingMapper.selectById(batchId);
            batchRemainingEntity.setGoodAmount(batchRemainingEntity.getGoodAmount() + amount);
            batchRemainingMapper.updateById(batchRemainingEntity);
        });
    }

    /**
     * @Author XieYu
     * @Description 批次数据添加或更新
     * @Date 2024/7/2 21:52
     * @Param [batch]
     * @return void
     */
    @Transactional(rollbackFor = Exception.class)
    public Long addOrUpdate(BatchEntity batch) {
        LambdaQueryWrapper<BatchEntity> updateWhereWrapper = new LambdaQueryWrapper<>();
        LambdaQueryWrapper<BatchEntity> whereWrapper = new LambdaQueryWrapper<>();
        // 查询对应的批次是否已经存在
        whereWrapper.eq(BatchEntity::getUserId, batch.getUserId());
        whereWrapper.eq(BatchEntity::getSkuId, batch.getSkuId());
        whereWrapper.eq(BatchEntity::getStashName, batch.getStashName());
        whereWrapper.eq(BatchEntity::getManufactureNo, batch.getManufactureNo());
        whereWrapper.eq(BatchEntity::getSupplierId, batch.getSupplierId());
        whereWrapper.eq(BatchEntity::getInboundNo, batch.getInboundNo());
        whereWrapper.eq(BatchEntity::getInboundTime, batch.getInboundTime());

        BatchEntity existBatch = batchMapper.selectOne(whereWrapper);
        long batchId;
        if (Objects.nonNull(existBatch)) {
            updateWhereWrapper.eq(BatchEntity::getId, existBatch.getId());
            updateWhereWrapper.eq(BatchEntity::getStatus, existBatch.getStatus());
            updateWhereWrapper.eq(BatchEntity::getGoodAmount, existBatch.getGoodAmount());
            updateWhereWrapper.eq(BatchEntity::getBadAmount, existBatch.getBadAmount());
            // 更新
            existBatch.setGoodAmount(existBatch.getGoodAmount() + batch.getGoodAmount());
            existBatch.setBadAmount(existBatch.getBadAmount() + batch.getBadAmount());
            existBatch.setStatus(1);
            batchMapper.update(existBatch, updateWhereWrapper);

            batchId = existBatch.getId();

            BatchRemainingEntity batchRemaining = batchRemainingMapper.selectById(batchId);
            LambdaQueryWrapper<BatchRemainingEntity> uw = new LambdaQueryWrapper<BatchRemainingEntity>()
                    .eq(BatchRemainingEntity::getBatchId, batchId)
                    .eq(BatchRemainingEntity::getGoodAmount, batchRemaining.getGoodAmount())
                    .eq(BatchRemainingEntity::getBadAmount, batchRemaining.getBadAmount());

            batchRemaining.setGoodAmount(batchRemaining.getGoodAmount() + batch.getGoodAmount());
            batchRemaining.setBadAmount(batchRemaining.getBadAmount() + batch.getBadAmount());
            batchRemainingMapper.update(batchRemaining, uw);
        } else {
            // 新增
            batch.setStatus(BatchStatus.AVAILABLE.getCode());
            batchMapper.insert(batch);
            batchId = batch.getId();
            BatchRemainingEntity batchRemaining = new BatchRemainingEntity();
            batchRemaining.setBatchId(batchId);
            batchRemaining.setGoodAmount(batch.getGoodAmount());
            batchRemaining.setBadAmount(batch.getBadAmount());
            batchRemainingMapper.insert(batchRemaining);
        }
        return batchId;
    }
}
